Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!
Quick question about POSIX threads programming in C. I'm doing an assignment that is supposed to teach us the use of semaphores. The gist is we make a bunch of threads that work together and have to use semaphores to not conflict with one another.

To force us to actually use semaphores, a requirement is that the main function for each thread takes no parameters. However, each thread outputs some messages as it executes that are supposed to include the thread's ID (not the LINUX assigned ID, but a local ID between 1 and the number of threads).

Is this even possible without passing a parameter into each thread? I can't think of any other way for each thread to identify which one it is.

Edit: Actually, can threads access some variable that indicates a unique thread ID assigned by the system? If that's the case I could make a dictionary between those IDs and my IDs. If there's a simpler way to do this I'll take that, but I supposed it would work in a pinch.

Eggnogium fucked around with this message at 20:22 on Mar 26, 2011

Adbot
ADBOT LOVES YOU

pseudorandom name
May 6, 2007

Make a global thread counter value which is incremented and read first thing by every thread. Don't forget to protect it against concurrent access. Store the value in a local variable in your thread function (if the function is simple), or in a thread-local global (using either __thread or pthread_{get,set}specific() if it isn't).

pseudorandom name fucked around with this message at 20:28 on Mar 26, 2011

Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!

pseudorandom name posted:

Make a global thread counter value which is incremented and read first thing by every thread. Don't forget to protect it against concurrent access.

Duuuur, thanks! That was too easy.

lemonadesweetheart
May 27, 2010

You sure your homework isn't asking you to use pthread_setspecific and pthread_getspecific? Or even just pthread_self for that matter.

You can't use a global variable to set thread specific information. It doesn't make any sense at all because it's shared across the threads. You can't guarantee ordering and you can't rely on the data in it and when it will be accessed.

pseudorandom name
May 6, 2007

lemonadesweetheart posted:

You sure your homework isn't asking you to use pthread_setspecific and pthread_getspecific? Or even just pthread_info for that matter.

You can't use a global variable to set thread specific information. It doesn't make any sense at all because it's shared across the threads. You can't guarantee ordering and you can't rely on the data in it and when it will be accessed.

code:
int get_unique_thread_id()
{
       static volatile int ids = 0;
       return __sync_add_and_fetch(&ids, 1);
}

lemonadesweetheart
May 27, 2010

My point is that doesn't really provide any useful information about the thread that's actually calling it. pthread_self is designed to do what he's trying to do (I think) because the thread id returned is actually meaningful

pseudorandom name
May 6, 2007

And his assignment explicitly forbids him from using pthread_self() or gettid(), probably specifically to force him to figure out how to assign each thread a unique small integer ID without passing the ID into the thread at the time of creation.

Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!
I think I may actually have to use pthread_self(). It's not forbidden in the assignment, I was just overcomplicating the task of transforming the thread IDs from pthread_self() into consecutive IDs between 1 and N.

But I'm already storing the IDs in a global array for the purpose of joining them at the end of the program, so I should just be able to use the index in that array where I find the ID as my own ID.

I do think pseudorandom name's suggestion fits more with the theme of the assignment, but we are explicitly forbidden from using extra local variables and the assignment doesn't specify any local variables associated with a thread's ID.

pthread_self() maps to the value saved in the first parameter to pthread_create(), right?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
If the goal is to learn about semaphores then an array of thread IDs seems very much against the spirit of the assignment. You should just be using a global volatile variable essentially the same way as pseudorandom's static one, but locking and unlocking a semaphore rather than using the atomic get-and-increment instruction used in his example. (Which I don't believe was really an example intended for you, but rather a very small example to prove lemonades' statement about the impossibility of using a global variable for unique thread data wrong.)

You could optionally write your own "lock-get-increment-unlock" function using semaphores to take the place of pseudorandom's use of __sync_add_and_fetch.

Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!
Thanks for the help everyone, I think I've worked it out. I have a syntax question now, though. I only use C every couple of months so I tend to forget the finer intricacies sometimes.

I have a struct type that I'm using in a linked list fashion:
code:
typedef struct
{
	int p;
	struct Book* next;
} Book;
I have a global variable that's a pointer to the struct:
code:
struct Book* shelves;
Sometimes I need to remove the first book, so I update my pointer:
code:
shelves = shelves->next;
But GCC gives me a compile-time error on that line:

quote:

error: dereferencing pointer to incomplete type

What am I overlooking here?

Sedro
Dec 31, 2008
Use Book instead of struct Book.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You haven't actually given the struct itself a name. You've created an anonymous struct, and then typedef'd it as Book. There is no such thing as a struct Book.

If you want to use just struct Book to refer to a struct, define it as:

code:
struct Book
{ //...
}
If you want to just use Book (no struct) do it as so:

code:
typedef struct
{ //...
} Book;
If you want to use both, then:

code:
typedef struct Book
{ //...
} Book;

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Eggnogium posted:

code:
typedef struct
{
	int p;
	struct Book* next;
} Book;
If you're going to reference the struct inside itself then it needs to have a name other than the typedef'd name (I think?) Since you're saying "struct Book" every time anyway you don't need to be typedeffing.

code:
struct Book {
  int p;
  struct Book *next;
};
If you want to refer to it as just Book rather than struct Book, later, then
code:
typedef struct s_Book {
  int p;
  struct s_Book *next;
} Book;
...would do the trick.

TasteMyHouse
Dec 21, 2006
I'm having a problem dynamically linking using g++. I know that this problem is just a simple syntax issue, but is gcc man page is daunting and google has been only somewhat helpful.

I have a library (sfml) that I'm trying to compile and link against. My ultimate goal is to have an archive that can be unarchived, built, and run without any alteration on the existing system (this is for a homework assignment, but the assignment has nothing to do with learning how to use gcc so I don't think this is doing my homework for me).

The library is distributed as so files, and basically all I need to do is tell gcc "hey, these functions are defined in a shared object, located here" but I don't have any idea how to do that.

nielsm
Jun 1, 2009



As far as I know, you simply need to have the functions forward-declared appropriately. Then, on your linking commandline, use the -L flag to add any additional library directories to the search path, and the -l flag (lowercase L) to specify the names of the libraries.

g++ -L/home/tastemyhouse/lib -lsfml foo.o bar.o -o baz

That should look for libsfml.so in /home/tastemyhouse/lib and use it for resolving symbols. Note that you don't specify the lib part nor the .so part of the library filename on the commandline.

UraniumAnchor
May 21, 2006

Not a walrus.
If you know exactly where the library file is you can just include that in your link step like you would an .o object too.

g++ -o program main.o libmylib.so

TasteMyHouse
Dec 21, 2006

nielsm posted:

As far as I know, you simply need to have the functions forward-declared appropriately. Then, on your linking commandline, use the -L flag to add any additional library directories to the search path, and the -l flag (lowercase L) to specify the names of the libraries.

g++ -L/home/tastemyhouse/lib -lsfml foo.o bar.o -o baz

That should look for libsfml.so in /home/tastemyhouse/lib and use it for resolving symbols. Note that you don't specify the lib part nor the .so part of the library filename on the commandline.
Yeah, I tried this before, and when I tried this now, I get an error:

$ g++ -L./lib -lsfml-system main.o -o main
/usr/bin/ld: cannot find -lsfml-system
collect2: ld returned 1 exit status

the name of the library I'm linking against is "libsfml-system.so.1.6", and I'm trying to store it in a "/lib/" folder in the same directory as the files I'm compiling -- hence the "./lib"

UraniumAnchor posted:

If you know exactly where the library file is you can just include that in your link step like you would an .o object too.

g++ -o program main.o libmylib.so
okay, I did this:
$ g++ -o main main.o ./lib/libsfml-system.so.1.6
which compiles, but when I try to execute:
./main: error while loading shared libraries: libsfml-system.so.1.6: cannot open shared object file: No such file or directory
I assume this is because there's some environment variable for dynamic libraries that I need to set? is there any way around this?

pseudorandom name
May 6, 2007

gcc -lx will search for libx.so, not libx.so.1.0. You need a libx.so symlink pointing to the actual library filename.

The dynamic linker will only search in a specific set of directories to find the libraries a binary depends on (the exact set depends on configuration, but at the very least it will contain /lib and /usr/lib or /lib64 and /usr/lib64). You can use the LD_LIBRARY_PATH environment variable to append to the configured search path; it is formatted like the PATH variable. See the ld.so man page for more information.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

roomforthetuna posted:

If you're going to reference the struct inside itself then it needs to have a name other than the typedef'd name (I think?)

It's complicated. Tag names (identifiers that follow the keywords struct, union, and enum) are in a different "namespace" from non-tag names, meaning that struct Book and Book in the same scope can mean completely different things. If you declare (struct Book;) or define (struct Book { ... }) a tag name, it introduces (or redeclares) a new type in the current scope. Any other use of a tag (e.g. struct Book *next;) looks for a type with that tag visible from the current scope; if it doesn't find one, then a new type is declared in the current scope. typedef names aren't tag names, and they also can't be used until the end of their declarator.

Here's Eggnogium's code again, for reference:

code:
typedef struct
{
	int p;
	struct Book* next;
} Book;

struct Book* shelves;
Since there's no identifier immediately after the struct keyword, the type defined here has no tag name (and cannot be referenced at all until we finish processing the typedef). The declaration of the field next incidentally declares a struct type with the tag-name Book; this type is completely unrelated to the type we're in the middle of defining. The later tag use (in the declaration of shelves) refers to this same new type, but since it's never actually been defined, it's still incomplete.

Anyway, you and Janin got most of the reasonable solutions. One that wasn't mentioned: if for some reason you really want to have the typedef available inside the definition, you can typedef a forward-declaration, like so:
code:
typedef struct Book Book;
struct Book {
  int p;
  Book *next;
};
EDIT: Oh, and note that the rules are significantly different in C++.

rjmccall fucked around with this message at 06:09 on Mar 27, 2011

Screeb
Dec 28, 2004

status: jiggled
I'm having troubles with mixing SSE and thread-local storage (VS2008). I get an "access violation reading location 0x00000000" when trying to use _mm_store_pd (or other similar functions I imagine) on a TLS array. Here's the gist of what I'm doing:

code:
// Foo.h

Class Foo
{
  public:
    void Bar();

    static __declspec(thread) __declspec(align(16)) double temp[16];
};


// Foo.cpp

__declspec(thread) __declspec(align(16)) double Foo::temp[16];

void Foo::Bar()
{
    // ...

    _mm_store_pd(&temp[i], m128dVal);  // Breaks here
}
It works fine if temp is local to Bar rather than TLS, or if only one thread is calling Bar. Is it possible to do what I want? Help computer.

Gerblyn
Apr 4, 2007

"TO BATTLE!"
Fun Shoe
What is the advantage of making an anonymous struct and then using typedef to give it a name, rather than simply making the named struct (i.e. struct Book{};). I see people do it sometimes, but I've never quite figured out the purpose of it.

Babysnakes!
Oct 29, 2009
I am trying to do a very basic C++ project for school. It involves taking a .txt database of the form

Student1name, student1address,student1gpa…etc
Student2name,student2address,student2gpa…etc

And importing it into an array stored on heap and then doing a bunch of other poo poo to it.

I am stuck on the first step. I am having trouble with the fact that the list has different types(string/char, int, double) and is separated by commas. I also don’t know what kind of array to use.

I spent like 5 hours on it yesterday and made very minimal progress. If you can answer my gay and uninteresting question, I will be forever indebted to you.

Gerblyn
Apr 4, 2007

"TO BATTLE!"
Fun Shoe
You want to make a struct that represents each record in the database:

code:
struct Record:
{
  string Name;
  string Address;
  float GPA;
};
and store your data in an array of those. Is storing the data in an array part of the assignment? If not, then storing the records in a vector would be much easier.

shrughes
Oct 11, 2008

(call/cc call/cc)

Gerblyn posted:

What is the advantage of making an anonymous struct and then using typedef to give it a name, rather than simply making the named struct (i.e. struct Book{};). I see people do it sometimes, but I've never quite figured out the purpose of it.

In C (but not C++) if you make a named struct you end up having to use the struct keyword everywhere you want to name the type. Using a typedef gets around that.

mr_jim
Oct 30, 2006

OUT OF THE DARK

Please don't do something like:
code:
typedef struct
{
    int x;
    float y;
} Foo;
typedef Foo *FooPointer;
The only time you should use a pointer typedef is for function pointers.

nielsm
Jun 1, 2009



Screeb posted:

I'm having troubles with mixing SSE and thread-local storage (VS2008). I get an "access violation reading location 0x00000000" when trying to use _mm_store_pd (or other similar functions I imagine) on a TLS array.

This is only a guess, but perhaps the SSE-ness and array-ness don't play together with TLS, and you need to add some indirection: Make a TLS pointer to your array, or do that but wrapped in a class (for easier memory management).

TasteMyHouse
Dec 21, 2006

pseudorandom name posted:

gcc -lx will search for libx.so, not libx.so.1.0. You need a libx.so symlink pointing to the actual library filename.

The dynamic linker will only search in a specific set of directories to find the libraries a binary depends on (the exact set depends on configuration, but at the very least it will contain /lib and /usr/lib or /lib64 and /usr/lib64). You can use the LD_LIBRARY_PATH environment variable to append to the configured search path; it is formatted like the PATH variable. See the ld.so man page for more information.
thanks, this solved my problem.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Screeb posted:

I'm having troubles with mixing SSE and thread-local storage (VS2008). I get an "access violation reading location 0x00000000" when trying to use _mm_store_pd (or other similar functions I imagine) on a TLS array.

It's probably an alignment thing; most SSE memory instructions require 16-byte alignment, and the processor actually raises the same hardware exception for unaligned accesses as for a page fault. Obviously, sometimes data that the compiler isn't correctly aligning will happen to get correctly aligned by accident, which is probably why it's working for some threads and not others. You can check this in a debugger by examining the TLS pointer at the time of the crash.

It's entirely possible that this is just a bug in VS2008; MSDN claims that it should work, so try re-arranging the code to use a more "standard" representation. For example, maybe it doesn't properly honor the alignment attribute on thread-local static data members, so try making it static to a single file instead.

If none of that works, you can always align it yourself: make an accessor to get at the TLS buffer, make the actual TLS data a char array with 15 extra bytes, and make the accessor round the TLS pointer up to proper alignment.

Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!

rjmccall posted:

words about structs

Thanks! That was very enlightening.

Okay, I was hoping for one last hint about semaphores. If this is getting too "Waahhh, do my homework for me!", feel free to ignore.

All the threads I have need to enter a function, and then wait in that function until all other threads have entered it (without busy waiting, so sem_wait needs to control the waiting). Here's the solution I've come up with but it feels hacked. Threads represent students and the idea is that they're meeting at the library so they have to wait until everyone shows up to proceed with the rest of the program:

code:
// Global variables
int libraryCount, numOfStudents;
sem_t inLibrary, enteringLibrary;

...

// Initializiation in main
int main(int argc, char* argv[])
{
    ...
    sem_init(&inLibrary, 0, 0);
    sem_init(&enteringLibrary, 0, 1);
    ...
}

...

void meet_at_the_library()
{
	print("Entering meet_at_the_library()");

	sem_wait(&enteringLibrary);
	
	// Wait until the last student shows up
	if(libraryCount != numOfStudents - 1)
	{
		libraryCount++;
		sem_post(&enteringLibrary);
		sem_wait(&inLibrary);
	}
	else
		sem_post(&enteringLibrary);
	
	sem_post(&inLibrary);
	
	print("Exiting meet_at_the_library()");
}
Basically, libraryCount keeps track of the number of students who have entered the library. enteringLibrary is just a mutex that makes sure that libraryCount is incremented properly. Then when the last student shows up, it kicks off a sem_post which cascades to all the other students waiting.

I don't really want a straight up solution cause I do enjoy figuring this stuff out, but if there is a less hacked way to do this I was just hoping for confirmation before I spend more hours trying to figure it out, and possibly a hint pointing in the right direction. Another problem with this method is that inLibrary has a value of 1 at the end, meaning that if this had to be done multiple times I'd be sunk (it doesn't, but that seems like a reasonable situation that could come up).

Deus Rex
Mar 5, 2005

edit: already beaten on this anyway

Neat Machine
May 5, 2008

heh
Unix noob question incoming...

My program needs to run when the following is entered into the command line:

my_program aFileToRead.txt number1 number2

(where the last three are all arguments for my_program)

How do I go about setting that up? Or am I just missing some kind of command that should be included but was not mentioned?

pseudorandom name
May 6, 2007

Are you asking how to access your command line arguments? Because those are the parameters to your main function.

nielsm
Jun 1, 2009



Either my_program needs to be in a directory on the path, or you need to include the directory name in the commandline.

If the program is in the current directory, and that isn't on the path, you'd do:
./my_program arg1 arg2 ...

The dot refers to the current directory, and is followed by a slash to refer to something inside it.


Edit: And if you're actually asking how to access the command line arguments, go look up what the argc and argv parameters to your main() function mean.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Or are you asking how to compile the program into something that can be run and make its filename my_program? If so, you probably need to ask Google "how to compile a C program in Unix".

Neat Machine
May 5, 2008

heh

nielsm posted:

Either my_program needs to be in a directory on the path, or you need to include the directory name in the commandline.

If the program is in the current directory, and that isn't on the path, you'd do:
./my_program arg1 arg2 ...

The dot refers to the current directory, and is followed by a slash to refer to something inside it.


Edit: And if you're actually asking how to access the command line arguments, go look up what the argc and argv parameters to your main() function mean.

./

Thank you :eng99:

lemonadesweetheart
May 27, 2010

nvm

lemonadesweetheart fucked around with this message at 04:49 on Mar 28, 2011

Screeb
Dec 28, 2004

status: jiggled

rjmccall posted:

It's probably an alignment thing; most SSE memory instructions require 16-byte alignment, and the processor actually raises the same hardware exception for unaligned accesses as for a page fault. Obviously, sometimes data that the compiler isn't correctly aligning will happen to get correctly aligned by accident, which is probably why it's working for some threads and not others. You can check this in a debugger by examining the TLS pointer at the time of the crash.

Good call - you're right, the alignment isn't working with TLS. Indeed, using _mm_storeu_pd works, though that's not optimal of course. In fact it seems any TLS variable doesn't align, so this:

rjmccall posted:

It's entirely possible that this is just a bug in VS2008; MSDN claims that it should work, so try re-arranging the code to use a more "standard" representation. For example, maybe it doesn't properly honor the alignment attribute on thread-local static data members, so try making it static to a single file instead.

...doesn't work either, unfortunately.

rjmccall posted:

If none of that works, you can always align it yourself: make an accessor to get at the TLS buffer, make the actual TLS data a char array with 15 extra bytes, and make the accessor round the TLS pointer up to proper alignment.

Looks like I might have to do this. I'm a bit concerned about performance though.

nielsm posted:

This is only a guess, but perhaps the SSE-ness and array-ness don't play together with TLS, and you need to add some indirection: Make a TLS pointer to your array, or do that but wrapped in a class (for easier memory management).

Yeah, this could also work, as I would just have one static array which is correctly aligned. Though the problem with that is it wouldn't automatically be as large as needed for X threads.


Thanks guys!

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Screeb posted:

Good call - you're right, the alignment isn't working with TLS. Indeed, using _mm_storeu_pd works, though that's not optimal of course. In fact it seems any TLS variable doesn't align, so this:

Strange. Is it all objects or just arrays? Maybe they didn't make this work until VS 2010.

Screeb posted:

Looks like I might have to do this. I'm a bit concerned about performance though.

Remember that the alternative requires a null-check and an extra load; it's probably a wash, plus this doesn't require an allocation you'll have to delete at thread exit.

Screeb
Dec 28, 2004

status: jiggled

rjmccall posted:

Strange. Is it all objects or just arrays? Maybe they didn't make this work until VS 2010.

Everything, by the looks of it. Well, I tried a double and an int (just like the MSDN example). Strange indeed. MSDN has docs for as far back as VS2003 claiming it works, so who knows.

rjmccall posted:

Remember that the alternative requires a null-check and an extra load; it's probably a wash, plus this doesn't require an allocation you'll have to delete at thread exit.

Which alternative are you referencing? I have several alternatives actually - I could do an unaligned store, a non-TLS array with TLS pointers, or access the data manually (ie .m128d_f64[]). Also, threads are long-lived in my app, so there's no concern over thread creation/destruction speed.

Annoyingly I can't find any references to this not working, so maybe I'm doing something weird somewhere else that's screwing it up. Maybe even my project properties? Hmm, I'll have to create a new project and see if I get the same issue there.

Edit: Nope. Even on a fresh project, as soon as Mr. __declspec(thread) appears, alignment goes out the window.

Screeb fucked around with this message at 10:36 on Mar 28, 2011

Adbot
ADBOT LOVES YOU

A MIRACLE
Sep 17, 2007

All right. It's Saturday night; I have no date, a two-liter bottle of Shasta and my all-Rush mix-tape... Let's rock.

Is it possible to use STL sort on something like

vector< vector< pair<int, myclass> > >

(sorting by the int)

I want to find out before I get in too deep.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply