Pthread sharing variables with pointers in C - c

I'm working on a C project using Pthread that needs to share some variables. There are several lines of code written yet and I just realized that using shared global variables doesn't work quite well because of the cache system.
I find on stackoverflow that a solution is to pass the adress of the variable (in my case it's more than one) to the thread function, what does it change?
Since my thread functions call other functions who will modify the globals, it's a bit painful to add a parameter to the chain of called functions where one function modify the globals.
So I was wondering, would it work to declare global pointers for each globals and use them to acess the global instead of the real globals?
I think it's a superficial inderiction but why wouldn't it work after all?
My program is an UDP network protocol whre networks look like rings or circled simple linked list. Instances of the program on the network are called entities.
An entity entity can insert on a ring or ask an entity to create another ring (dupplication), so the other entity would be on two ring.
The interface is sort of a shell where commands can leads to sending messages on the ring. Messages circle all over the rings after being stopped when they have ever been seen.
The shell is in the main thread, there is a thread for message treatment, another to manage insertion, and there is also a thread to detect broken rings. The problems is located in the ring tester thread. The thread initialize a global array (volatile short ring_check[NRING]) of size of the maximum ring numbers for an entity, initialize the first element with 0 according to the actual number of rings and the rest with -1, after that it send a test message in each ring and sleeps during a timeout of 30sec. When the timeout has finished, it checks for the values in the array.
The values are changed by the thread for message treatment, when a test message went went back, it detects it by its content and write -1 to the appropriate ring_check element.
The problem is that after a dupplication, the two rings are tested but the checking for the second failed (ring_check[1] == 0) and I really don't know why... The test message is received, immediately after the sending, after the message treatment modifies ring_check[1] to 0 I print it to see if the change is really made and it prints 1. But about 20 to 30sec later, the ring_tester wake up from his sleeping time and it reads 0 in ring_check[1].
short volatile ring_check[NRING+1];
// The function in the ring tester thread
static void test_ring() {
// initialize ring_check array
debug("ring_tester", GREEN "setting ring_check to -1...");
char port_diff[5];
// send test messages in each rings
int fixed_nring = getnring();
for (int i = fixed_nring+1; i < NRING; ++i) {
ring_check[i] = -1;
}
for (int i = 0; i < fixed_nring + 1; i++) {
debug("ring_tester", GREEN "setting ring_check %d to 0...", i);
ring_check[i] = 0;
itoa4(port_diff, ent.mdiff_port[i]);
debug("ring_tester", GREEN "sending test to ring %d...", i);
sendmessage(i, "TEST", "%s %s", ent.mdiff_ip[i], port_diff);
}
debug("test_ring", GREEN "timeout beginning...");
sleep(timeout);
debug("test_ring", GREEN "end of timeout.");
for (int i = 0; i < fixed_nring + 1 && ring_check[i] != -1; i++) {
debug("test_ring", GREEN "ring_check[%d]:%d", i, ring_check[i]);
if (ring_check[i]) {
debug("test_ring", GREEN "ring %d: checked.", i);
continue;
}
else {
debug("test_ring", GREEN "ring %d: checking failed. Ring broken...", i);
continue;
}
}
// The function called by the message treatment thread
static int action_test(char *message, char *content, int lookup_flag) {
debug("action_test", RED "entering function...");
if (content[15] != ' ' || content[20] != 0) {
debug("action_test", RED "content not following the protocol."\
"content: \"%s\"", content);
return 1;
}
if (lookup_flag) {
char mdiff_port[5];
int fixed_nring = getnring();
for (int i = 0; i < fixed_nring + 1 && ring_check[i] != -1; ++i) {
itoa4(mdiff_port, ent.mdiff_port[i]);
// find ring associated with message and actualize the checking
if (strncmp(content, ent.mdiff_ip[i], 15) == 0 &&
strncmp(&content[16], mdiff_port, 4) == 0 &&
ring_check[i] != -1) {
ring_check[i] = 1;
debug("action_test",
RED "correspondance found, ring_check[%d]:%d", i, ring_check[i]);
return 0;
}
}
}
else {
sendpacket_all(message);
}
return 0;
}

You could define a global structure such as thread_inputparam. Put all the global variables' addresses in it and send to all threads, the adress of this structure variable.
int global1;
struct thread_input {
int *g1;
// add other globals'addresses
}thread_inputparam;
thread_inputparam.g1=&global1;

Related

Measure wall clock time before and after a function

I am measuring wall time through the use of clock_gettime() found in . It works perfectly fine when i use it in main() but not the way i am attempting to use it.
I am familiarizing myself with the linux scheduler and i am measuring performance on different parts.
I want to be able to measure Waiting time which is defined by "the total time a thread spends in the ready queue" (how long until it starts executing the function).
Easily enough i can measure this by setting a clock_gettime() before the thread function and another right inside the function. However the problem i am having is that the time inside the thread function is lower than the one outside, giving us a negative time.
I am running this on my windows pc through ubuntu.
what could the problem be?
code:
clock_gettime(CLOCK_REALTIME,&data.before);
thread_array[i-1] = data;
if(pthread_create(&tids[i],&attr,workLoad,(void*) &data) != 0){
perror("Could not create thread");
return 1;
}
}
for(int i = 1;i < threadAmount; i++){
if(pthread_join(tids[i],NULL)!= 0){
perror("Thread could not wait");
return 1;
}
}
and here is my threadfunc:
void *workLoad(void *args)
{
threadData* data = (threadData*) args;
clock_gettime(CLOCK_REALTIME,&data->after);
int loopAmount = data->loopAmount;
int counter = 0;
for(int i = 0; i < loopAmount; i++){
counter++;
}
return NULL;
}
result of time intervall
In the following code:
clock_gettime(CLOCK_REALTIME,&data.before);
thread_array[i-1] = data;
if(pthread_create(&tids[i],&attr,workLoad,(void*) &data) != 0){
data seems to be a local variable whose address you pass to the thread. You also copy this variable into thread_array[i-1]. If you then do thread_array[i-1].after - thread_array[i-1].before then that means that the thread updates a wrong variable. You need to pass &thread_array[i-1] to that thread, e.g.:
if(pthread_create(&tids[i],&attr,workLoad,(void*)&thread_array[i-1]) != 0){

Strategy for cycling trough preexisting set of variables in c

I’m trying to program a HMI console to read a file from an USB pen drive and display its data on the screen. This is a csv file and the objective is to store the interpreted data to HMI console memory, which the HMI console later interprets. The macros on these consoles run in C (not C++).
I have no issue with both reading and interpreting the file, the issue that the existing function (not accessible to me, shown below) to write in the console memory only interprets char.
int WriteLocal( const char *type, int addr, int nRegs, void *buf , int flag );
Parameter: type is the string of "LW","LB" etc;
address is the Operation address ;
nRegs is the length of read or write ;
buf is the buffer which store the reading or writing data
flag is 0,then codetype is BIN,is 1 then codetype is BCD;
return value : 1 , Operation success
0 , Operation fail.
As my luck would have it I need to write integer values. What are available to me are the variables for each memory position. These are preexisting and are named individually such as:
int WR_LW200;
int WR_LW202;
int WR_LW204;
...
int WR_LW20n;
Ideally we could have a vector with all the names of the variables but unfortunately this is not possible. I could manually write every single variable but I need to do 300 of these…
must be a better way, right?
Just to give you a look on how it ended up looking:
int* arr[50][5] = { {&WR_LW200, &WR_LW400, &WR_LW600, &WR_LW800, &WR_LW1000},
{&WR_LW202, &WR_LW402, &WR_LW602, &WR_LW802, &WR_LW1002},
{&WR_LW204, &WR_LW404, &WR_LW604, &WR_LW804, &WR_LW1004},
{&WR_LW206, &WR_LW406, &WR_LW606, &WR_LW806, &WR_LW1006},
{&WR_LW208, &WR_LW408, &WR_LW608, &WR_LW808, &WR_LW1008},
{&WR_LW210, &WR_LW410, &WR_LW610, &WR_LW810, &WR_LW1010},
{&WR_LW212, &WR_LW412, &WR_LW612, &WR_LW812, &WR_LW1012},
{&WR_LW214, &WR_LW414, &WR_LW614, &WR_LW814, &WR_LW1014},
{&WR_LW216, &WR_LW416, &WR_LW616, &WR_LW816, &WR_LW1016},
{&WR_LW218, &WR_LW418, &WR_LW618, &WR_LW818, &WR_LW1018},
{&WR_LW220, &WR_LW420, &WR_LW620, &WR_LW820, &WR_LW1020},
{&WR_LW222, &WR_LW422, &WR_LW622, &WR_LW822, &WR_LW1022},
{&WR_LW224, &WR_LW424, &WR_LW624, &WR_LW824, &WR_LW1024},
{&WR_LW226, &WR_LW426, &WR_LW626, &WR_LW826, &WR_LW1026},
{&WR_LW228, &WR_LW428, &WR_LW628, &WR_LW828, &WR_LW1028},
{&WR_LW230, &WR_LW430, &WR_LW630, &WR_LW830, &WR_LW1030},
{&WR_LW232, &WR_LW432, &WR_LW632, &WR_LW832, &WR_LW1032},
{&WR_LW234, &WR_LW434, &WR_LW634, &WR_LW834, &WR_LW1034},
{&WR_LW236, &WR_LW436, &WR_LW636, &WR_LW836, &WR_LW1036},
{&WR_LW238, &WR_LW438, &WR_LW638, &WR_LW838, &WR_LW1038},
{&WR_LW240, &WR_LW440, &WR_LW640, &WR_LW840, &WR_LW1040},
{&WR_LW242, &WR_LW442, &WR_LW642, &WR_LW842, &WR_LW1042},
{&WR_LW244, &WR_LW444, &WR_LW644, &WR_LW844, &WR_LW1044},
{&WR_LW246, &WR_LW446, &WR_LW646, &WR_LW846, &WR_LW1046},
{&WR_LW248, &WR_LW448, &WR_LW648, &WR_LW848, &WR_LW1048},
{&WR_LW250, &WR_LW450, &WR_LW650, &WR_LW850, &WR_LW1050},
{&WR_LW252, &WR_LW452, &WR_LW652, &WR_LW852, &WR_LW1052},
{&WR_LW254, &WR_LW454, &WR_LW654, &WR_LW854, &WR_LW1054},
{&WR_LW256, &WR_LW456, &WR_LW656, &WR_LW856, &WR_LW1056},
{&WR_LW258, &WR_LW458, &WR_LW658, &WR_LW858, &WR_LW1058},
{&WR_LW260, &WR_LW460, &WR_LW660, &WR_LW860, &WR_LW1060},
{&WR_LW262, &WR_LW462, &WR_LW662, &WR_LW862, &WR_LW1062},
{&WR_LW264, &WR_LW464, &WR_LW664, &WR_LW864, &WR_LW1064},
{&WR_LW266, &WR_LW466, &WR_LW666, &WR_LW866, &WR_LW1066},
{&WR_LW268, &WR_LW468, &WR_LW668, &WR_LW868, &WR_LW1068},
{&WR_LW270, &WR_LW470, &WR_LW670, &WR_LW870, &WR_LW1070},
{&WR_LW272, &WR_LW472, &WR_LW672, &WR_LW872, &WR_LW1072},
{&WR_LW274, &WR_LW474, &WR_LW674, &WR_LW874, &WR_LW1074},
{&WR_LW276, &WR_LW476, &WR_LW676, &WR_LW876, &WR_LW1076},
{&WR_LW278, &WR_LW478, &WR_LW678, &WR_LW878, &WR_LW1078},
{&WR_LW280, &WR_LW480, &WR_LW680, &WR_LW880, &WR_LW1080},
{&WR_LW282, &WR_LW482, &WR_LW682, &WR_LW882, &WR_LW1082},
{&WR_LW284, &WR_LW484, &WR_LW684, &WR_LW884, &WR_LW1084},
{&WR_LW286, &WR_LW486, &WR_LW686, &WR_LW886, &WR_LW1086},
{&WR_LW288, &WR_LW488, &WR_LW688, &WR_LW888, &WR_LW1088},
{&WR_LW290, &WR_LW490, &WR_LW690, &WR_LW890, &WR_LW1090},
{&WR_LW292, &WR_LW492, &WR_LW692, &WR_LW892, &WR_LW1092},
{&WR_LW294, &WR_LW494, &WR_LW694, &WR_LW894, &WR_LW1094},
{&WR_LW296, &WR_LW496, &WR_LW696, &WR_LW896, &WR_LW1096},
{&WR_LW298, &WR_LW498, &WR_LW698, &WR_LW898, &WR_LW1098} };
Big right? I had consurns that this HMI would have issues with such an approach but it did the job. The code below runs trough a string that comes from the csv file. This code runs inside another while cycle to cycle trough the multi dimensional array.
it's a little crude but works.
while (i<=5)
{
memset(lineTemp, 0, sizeof lineTemp); // clear lineTemp array
while (lineFromFile[index] != delimiter)
{
if (lineFromFile[index] != delimiter && lineFromFile[index] != '\0') { lineTemp[j] = lineFromFile[index]; index++; j++; }
if (lineFromFile[index] == '\0') { i = 5; break; }
}
index++;
lineTemp[j] = '\0'; // NULL TERMINATION
j = 0;
if (i == -1) { WriteLocal("LW",temp,3,lineTemp,0); }
if (i >= 0 && i<=5) { *(arr[x][i]) = atoi(lineTemp); }
i++;
}
Thanks again for the tip.
Cheers

Synchronizing the result of threads with incremented shared variable and condition

The title might not appear particularly clear, but the code explains itself:
int shared_variable;
int get_shared_variable() {
int result;
pthread_mutex_lock(&shared_variable_mutex);
result = shared_variable;
pthread_mutex_unlock(&shared_variable_mutex);
return result;
}
void* thread_routine(void *arg) {
while (get_shared_variable() < 5000) {
printf();
printf();
sleep(2);
int i = 0;
while (pthread_mutex_trylock(&foo_mutexes[i]) != 0) {
i++;
pthread_mutex_lock(&foo_count_mutex);
if (i == foo_count) {
pthread_mutex_unlock(&foo_count_mutex);
sleep(1); // wait one second and retry
i = 0;
}
pthread_mutex_unlock(&foo_count_mutex);
}
pthread_mutex_lock(&shared_variable_mutex);
shared_variable += 10;
pthread_mutex_unlock(&shared_variable_mutex);
}
return NULL;
}
I'm passing thread_routine to a pthread_create (pretty standard), but I'm having a problem with the synchronization of the result. Basically, the problem is that the first thread checks the while condition, it passes, and then another thread checks it, it passes too. However, when the first thread finishes and shared_variable reaches 5000, the second thread has not yet finished and it adds up another 10 and the end result becomes 5010 (or NUM_OF_THREADS - 1 * 10 if I run more than two) at the end, while the whole process should end at 5000.
Another issue is that in // do some work I output something on the screen, so the whole thing inside the loop should pretty much work as a transaction in database terms. I can't seem to figure out how to solve this problem, but I suppose there's something simple that I'm missing. Thanks in advance.
This answer may or may not be what you are after. Because as explained in the comments your description of the expected behaviour of the program is incomplete. Without the exact expected behaviour it is difficult to give a full answer. But since you ask, here is a possible structure of the program based on the code shown. The main principle it is illustrating is that the critical section for shared_variable needs to be both minimal and complete.
int shared_variable;
void* thread_routine(void *arg)
{
while (1) {
pthread_mutex_lock(&shared_variable_mutex);
if (shared_variable >= 5000) {
pthread_mutex_unlock(&shared_variable_mutex);
break;
}
shared_variable += 10;
pthread_mutex_unlock(&shared_variable_mutex);
/* Other code that doesn't use shared_variable goes here */
}
return NULL;
}

C pthread printing "anomaly"

I've been doing a program in C which uses a series of threads to represent cars crossing a bridge, the function I'm doing right know is the one that prints the "state" of the bridge at a certain moment, so it shows where cars (threads) are in the bridge and at which position.
The problem is this; when there is only ONE thread crossing, the function prints properly and you can see the representation of the car advancing through the bridge. But when there are more threads crossing the function gets crazy and sometimes you can see a bridge and a half, or two bridges or some other crazy things. I tried to solve it creating a pthread_mutex for that function but it wasn't the solution, or at least I'm not using it at the right place.
Every thread call this function as it advances through the bridge (the bridge is an array)
Sorry if I failed to make it clear; here is the function and thanks for your time:
void printBridge(bridge *pBridge, int direction) {
system("clear");
int i;
if (direction == WEST) {
for (i = 0; i < bridgeSize; i++) {
pthread_mutex_lock(&print);
if (pBridge->cellState[i] == 0) { //this means the position at the array isn't occupied
fprintf(stderr, "\t");
} else if (pBridge->cellState[i] == 1) { //this means a car is at that position
fprintf(stderr, " ###>"); //the cars are represented by ###>
}
pthread_mutex_unlock(&print);
}
} else {
for (i = bridgeSize - 1; i >= 0; i--) { //if going the other direction
pthread_mutex_lock(&print);
if (pBridge->cellState[i] == 0) {
fprintf(stderr, "\t");
} else if (pBridge->cellState[i] == 1) {
fprintf(stderr, "<### ");
}
pthread_mutex_unlock(&print);
}
}
printf("\n--------------------------------------------------------------------------\n");
fprintf(stderr, "\n Direction= %d", pBridge->direction);
sleep(1); //because I need to see what's going on
}
So...a proper print would be like this:
<### <###
--------------------------------------------------------------------------
But sometimes it gets as messy as this:
<### <### <### <###
--------------------------------------------------------------------------
<### <### <### <###
Direction= 1--------------------------------------------------------------------------
Could it be because of the system("clear") being executed by many threads at a time?
SOLVED:
Solved calling the pthread_mutex_lock and unlock outside the function using a mutex for each position of the array ( bridge):
pthread_mutex_lock(&pBridge->mutexBridge[i]);
pBridge->cellState[i]=1;
printBridge(pBridge,dir);
pBridge->cellState[i]=0;
pthread_mutex_unlock(&pPuente->mutexBridge[i]);
And for some reason, inside the printBridge function, wrapped the system("clear") with mutex as well:
pthread_mutex_lock(&print);
system("clear");
pthread_mutex_unlock(&print);
Not doing the above gave me crazy prints. Thanks to pat for the help
You are only locking around printing of individual cars and spaces, so, when multiple threads are printing, they will interleave the bridges on a car by car basis. You need to acquire the mutex before you start printing the bridge and release it when you are done. In this way, threads will interleave whole bridges instead of individual cars.

linux kernel + conditional statements

I basically am running into a very odd situation in a system call that I am writing. I want to check some values if they are the same return -2 which indicates a certain type of error has occurred. I am using printk() to print the values of the variables right before my "else if" and it says that they are equal to one another but yet the conditional is not being executed (i.e. we don't enter the else if) I am fairly new to working in the kernel but this seems very off to me and am wondering if there is some nuance of working in the kernel I am not aware of so if anyone could venture a guess as to why if I know the values of my variables the conditional would not execute I would really appreciate your help
//---------------------------------------//
/* sys_receiveMsg421()
Description:
- Copies the first message in the mailbox into <msg>
*/
asmlinkage long sys_receiveMsg421(unsigned long mbxID, char *msg, unsigned long N)
{
int result = 0;
int mboxIndex = checkBoxId(mbxID);
int msgIndex = 0;
//acquire the lock
down_interruptible(&sem);
//check to make sure the mailbox with <mbxID> exists
if(!mboxIndex)
{
//free our lock
up(&sem);
return -1;
}
else
mboxIndex--;
printk("<1>mboxIndex = %d\nNumber of messages = %dCurrent Msg = %d\n",mboxIndex, groupBox.boxes[mboxIndex].numMessages, groupBox.boxes[mboxIndex].currentMsg );
//check to make sure we have a message to recieve
-----------CODE NOT EXECUTING HERE------------------------------------------------
if(groupBox.boxes[mboxIndex].numMessages == groupBox.boxes[mboxIndex].currentMsg)
{
//free our lock
up(&sem);
return -2;
}
//retrieve the message
else
{
//check to make sure the msg is a valid pointer before continuing
if(!access_ok(VERIFY_READ, msg, N * sizeof(char)))
{
printk("<1>Access has been denied for %lu\n", mbxID);
//free our lock
up(&sem);
return -1;
}
else
{
//calculate the index of the message to be retrieved
msgIndex = groupBox.boxes[mboxIndex].currentMsg;
//copy from kernel to user variable
result = copy_to_user(msg, groupBox.boxes[mboxIndex].messages[msgIndex], N);
//increment message position
groupBox.boxes[mboxIndex].currentMsg++;
//free our lock
up(&sem);
//return number of bytes copied
return (N - result);
}
}
}
UPDATE: Solved my problem by just changing the return value to something else and it works fine very weird though
Please remember to use punctuation; I don't like running out of breath while reading questions.
Are you sure the if block isn't being entered? A printk there (and another in the corresponding else block) would take you one step further, no?
As for the question: No, there isn't anything specific to kernel code that would make this not work.
And you seem to have synchronization covered, too. Though: I see that you're acquiring mboxIndex outside the critical section. Could that cause a problem? It's hard to tell from this snippet, which doesn't even have groupBox declared.
Perhaps numMessages and/or currentMsg are defined as long?
If so, your printk, which uses %d, would print just some of the bits, so you may think they're equal while they are not.

Resources